//! # 通用权限检查器
//!
//! 提供标准的权限检查实现，避免在各个模块中重复实现相同的权限检查逻辑。

use crate::auth::types::*;
use async_trait::async_trait;

/// 权限检查配置
#[derive(Debug, Clone)]
pub struct PermissionCheckConfig {
    /// 管理员角色名称列表
    pub admin_roles: Vec<String>,
    /// 超级权限标识符
    pub super_permission: String,
    /// 是否启用通配符权限检查
    pub enable_wildcard: bool,
    /// 是否启用层级权限检查
    pub enable_hierarchy: bool,
    /// 权限层级分隔符
    pub hierarchy_separator: String,
}

impl Default for PermissionCheckConfig {
    fn default() -> Self {
        Self {
            admin_roles: vec!["admin".to_string(), "super_admin".to_string()],
            super_permission: "*".to_string(),
            enable_wildcard: true,
            enable_hierarchy: true,
            hierarchy_separator: ":".to_string(),
        }
    }
}

/// 通用权限检查器
pub struct CommonPermissionChecker {
    config: PermissionCheckConfig,
}

impl CommonPermissionChecker {
    /// 创建新的权限检查器
    pub fn new() -> Self {
        Self {
            config: PermissionCheckConfig::default(),
        }
    }

    /// 使用指定配置创建权限检查器
    pub fn with_config(config: PermissionCheckConfig) -> Self {
        Self { config }
    }

    /// 内部权限检查逻辑
    pub fn check_permission_internal(&self, principal: &Principal, permission: &str) -> bool {
        // 1. 检查管理员权限
        if self.is_admin(principal) {
            return true;
        }

        // 2. 检查超级权限
        if principal.has_permission(&self.config.super_permission) {
            return true;
        }

        // 3. 检查精确权限
        if principal.has_permission(permission) {
            return true;
        }

        // 4. 检查通配符权限
        if self.config.enable_wildcard && self.check_wildcard_permission(principal, permission) {
            return true;
        }

        // 5. 检查层级权限
        if self.config.enable_hierarchy && self.check_hierarchy_permission(principal, permission) {
            return true;
        }

        false
    }

    /// 检查是否为管理员
    fn is_admin(&self, principal: &Principal) -> bool {
        // 检查主体类型
        if principal.is_admin() {
            return true;
        }

        // 检查管理员角色
        for admin_role in &self.config.admin_roles {
            if principal.has_role(admin_role) {
                return true;
            }
        }

        false
    }

    /// 检查通配符权限
    fn check_wildcard_permission(&self, principal: &Principal, permission: &str) -> bool {
        for user_permission in principal.get_permissions() {
            if user_permission.ends_with("*") {
                let prefix = &user_permission[..user_permission.len() - 1];
                if permission.starts_with(prefix) {
                    return true;
                }
            }
        }
        false
    }

    /// 检查层级权限
    fn check_hierarchy_permission(&self, principal: &Principal, permission: &str) -> bool {
        let parts: Vec<&str> = permission.split(&self.config.hierarchy_separator).collect();
        
        // 检查各级权限
        for i in 1..parts.len() {
            let partial_permission = parts[..i].join(&self.config.hierarchy_separator) + ":" + "*";
            if principal.has_permission(&partial_permission) {
                return true;
            }
        }

        false
    }

    /// 生成资源权限标识符
    pub fn generate_resource_permission(&self, resource: &Resource) -> String {
        format!("{}{}{}{}{}",
            resource.service,
            self.config.hierarchy_separator,
            resource.method.to_lowercase(),
            self.config.hierarchy_separator,
            resource.path
        )
    }

    /// 检查资源权限（带有额外的方法级权限检查）
    pub fn check_resource_permission_extended(&self, principal: &Principal, resource: &Resource) -> bool {
        // 1. 使用标准权限检查
        let required_permission = self.generate_resource_permission(resource);
        if self.check_permission_internal(principal, &required_permission) {
            return true;
        }

        // 2. 检查方法级权限
        let method_permission = self.generate_method_permission(resource);
        if self.check_permission_internal(principal, &method_permission) {
            return true;
        }

        // 3. 检查读写权限
        if self.check_read_write_permission(principal, resource) {
            return true;
        }

        false
    }

    /// 生成方法级权限
    fn generate_method_permission(&self, resource: &Resource) -> String {
        format!("*{}{}{}*", 
            self.config.hierarchy_separator,
            resource.method.to_lowercase(),
            self.config.hierarchy_separator
        )
    }

    /// 检查读写权限
    fn check_read_write_permission(&self, principal: &Principal, resource: &Resource) -> bool {
        let method = resource.method.to_uppercase();
        
        match method.as_str() {
            "GET" | "HEAD" | "OPTIONS" => {
                let read_permission = format!("{}{}read", resource.service, self.config.hierarchy_separator);
                principal.has_permission(&read_permission)
            }
            "POST" | "PUT" | "PATCH" | "DELETE" => {
                let write_permission = format!("{}{}write", resource.service, self.config.hierarchy_separator);
                principal.has_permission(&write_permission)
            }
            _ => false,
        }
    }
}

impl Default for CommonPermissionChecker {
    fn default() -> Self {
        Self::new()
    }
}

#[async_trait]
impl PermissionChecker for CommonPermissionChecker {
    async fn check(&self, principal: &Principal, permission: &str) -> AuthResult<bool> {
        Ok(self.check_permission_internal(principal, permission))
    }

    async fn check_resource(&self, principal: &Principal, resource: &Resource) -> AuthResult<bool> {
        Ok(self.check_resource_permission_extended(principal, resource))
    }
}

/// 权限检查器工厂
pub struct PermissionCheckerFactory;

impl PermissionCheckerFactory {
    /// 创建默认权限检查器
    pub fn create_default() -> Box<dyn PermissionChecker> {
        Box::new(CommonPermissionChecker::new())
    }

    /// 创建配置权限检查器
    pub fn create_with_config(config: PermissionCheckConfig) -> Box<dyn PermissionChecker> {
        Box::new(CommonPermissionChecker::with_config(config))
    }

    /// 创建简单权限检查器（只检查精确匹配）
    pub fn create_simple() -> Box<dyn PermissionChecker> {
        let config = PermissionCheckConfig {
            admin_roles: vec!["admin".to_string()],
            super_permission: "*".to_string(),
            enable_wildcard: false,
            enable_hierarchy: false,
            hierarchy_separator: ":".to_string(),
        };
        Box::new(CommonPermissionChecker::with_config(config))
    }

    /// 创建层级权限检查器
    pub fn create_hierarchical(separator: String, admin_roles: Vec<String>) -> Box<dyn PermissionChecker> {
        let config = PermissionCheckConfig {
            admin_roles,
            super_permission: "*".to_string(),
            enable_wildcard: true,
            enable_hierarchy: true,
            hierarchy_separator: separator,
        };
        Box::new(CommonPermissionChecker::with_config(config))
    }
}



#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_common_permission_checker() {
        let checker = CommonPermissionChecker::new();

        // 测试管理员权限
        let admin = Principal::new(
            "admin1".to_string(),
            "Admin User".to_string(),
            PrincipalType::Admin,
        );
        assert!(checker.check_permission_internal(&admin, "any:permission"));

        // 测试精确权限
        let user = Principal::new(
            "user1".to_string(),
            "Regular User".to_string(),
            PrincipalType::User,
        ).add_permission("read:users".to_string());
        
        assert!(checker.check_permission_internal(&user, "read:users"));
        assert!(!checker.check_permission_internal(&user, "write:users"));
    }

    #[test]
    fn test_wildcard_permissions() {
        let checker = CommonPermissionChecker::new();
        
        let user = Principal::new(
            "user1".to_string(),
            "User".to_string(),
            PrincipalType::User,
        ).add_permission("users:*".to_string());

        assert!(checker.check_permission_internal(&user, "users:read"));
        assert!(checker.check_permission_internal(&user, "users:write"));
        assert!(!checker.check_permission_internal(&user, "posts:read"));
    }

    #[test]
    fn test_resource_permission() {
        let checker = CommonPermissionChecker::new();
        
        let resource = Resource::new(
            "user-service".to_string(),
            "/api/users".to_string(),
            "GET".to_string(),
        );

        let user = Principal::new(
            "user1".to_string(),
            "User".to_string(),
            PrincipalType::User,
        ).add_permission("user-service:get:/api/users".to_string());

        assert!(checker.check_resource_permission_extended(&user, &resource));
    }

    #[test]
    fn test_read_write_permissions() {
        let checker = CommonPermissionChecker::new();
        
        let get_resource = Resource::new(
            "users".to_string(),
            "/api/users".to_string(),
            "GET".to_string(),
        );

        let post_resource = Resource::new(
            "users".to_string(),
            "/api/users".to_string(),
            "POST".to_string(),
        );

        let read_user = Principal::new(
            "user1".to_string(),
            "User".to_string(),
            PrincipalType::User,
        ).add_permission("users:read".to_string());

        let write_user = Principal::new(
            "user2".to_string(),
            "User".to_string(),
            PrincipalType::User,
        ).add_permission("users:write".to_string());

        assert!(checker.check_resource_permission_extended(&read_user, &get_resource));
        assert!(!checker.check_resource_permission_extended(&read_user, &post_resource));
        assert!(checker.check_resource_permission_extended(&write_user, &post_resource));
        assert!(!checker.check_resource_permission_extended(&write_user, &get_resource));
    }

    #[tokio::test]
    async fn test_permission_checker_factory() {
        let checker = PermissionCheckerFactory::create_default();
        
        let admin = Principal::new(
            "admin".to_string(),
            "Admin".to_string(),
            PrincipalType::Admin,
        );

        let result = checker.check(&admin, "any:permission").await;
        assert!(result.is_ok());
        assert!(result.unwrap());
    }
}